home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / gxshade1.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  20.9 KB  |  687 lines

  1. /* Copyright (C) 1998, 2000 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of AFPL Ghostscript.
  4.   
  5.   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  6.   distributor accepts any responsibility for the consequences of using it, or
  7.   for whether it serves any particular purpose or works at all, unless he or
  8.   she says so in writing.  Refer to the Aladdin Free Public License (the
  9.   "License") for full details.
  10.   
  11.   Every copy of AFPL Ghostscript must include a copy of the License, normally
  12.   in a plain ASCII text file named PUBLIC.  The License grants you the right
  13.   to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14.   conditions described in the License.  Among other things, the License
  15.   requires that the copyright notice and this notice be preserved on all
  16.   copies.
  17. */
  18.  
  19. /*$Id: gxshade1.c,v 1.5.2.2 2000/10/30 22:15:05 raph Exp $ */
  20. /* Rendering for non-mesh shadings */
  21. #include "math_.h"
  22. #include "memory_.h"
  23. #include "gx.h"
  24. #include "gserrors.h"
  25. #include "gsmatrix.h"        /* for gscoord.h */
  26. #include "gscoord.h"
  27. #include "gspath.h"
  28. #include "gxcspace.h"
  29. #include "gxdcolor.h"
  30. #include "gxfarith.h"
  31. #include "gxfixed.h"
  32. #include "gxistate.h"
  33. #include "gxpath.h"
  34. #include "gxshade.h"
  35.  
  36. /* ================ Utilities ================ */
  37.  
  38. /* Check whether 2 colors fall within the smoothness criterion. */
  39. private bool
  40. shade_colors2_converge(const gs_client_color cc[2],
  41.                const shading_fill_state_t * pfs)
  42. {
  43.     int ci;
  44.  
  45.     for (ci = pfs->num_components - 1; ci >= 0; --ci)
  46.     if (fabs(cc[1].paint.values[ci] - cc[0].paint.values[ci]) >
  47.         pfs->cc_max_error[ci]
  48.         )
  49.         return false;
  50.     return true;
  51. }
  52.  
  53. /* Fill a user space rectangle that is also a device space rectangle. */
  54. private int
  55. shade_fill_device_rectangle(const shading_fill_state_t * pfs,
  56.                 const gs_fixed_point * p0,
  57.                 const gs_fixed_point * p1,
  58.                 gx_device_color * pdevc)
  59. {
  60.     gs_imager_state *pis = pfs->pis;
  61.     fixed xmin, ymin, xmax, ymax;
  62.     int x, y;
  63.  
  64.     if (p0->x < p1->x)
  65.     xmin = p0->x, xmax = p1->x;
  66.     else
  67.     xmin = p1->x, xmax = p0->x;
  68.     if (p0->y < p1->y)
  69.     ymin = p0->y, ymax = p1->y;
  70.     else
  71.     ymin = p1->y, ymax = p0->y;
  72.  
  73.     /* See gx_default_fill_path for an explanation of the tweak below. */
  74.     xmin -= pis->fill_adjust.x;
  75.     if (pis->fill_adjust.x == fixed_half)
  76.     xmin += fixed_epsilon;
  77.     xmax += pis->fill_adjust.x;
  78.     ymin -= pis->fill_adjust.y;
  79.     if (pis->fill_adjust.y == fixed_half)
  80.     ymin += fixed_epsilon;
  81.     ymax += pis->fill_adjust.y;
  82.     x = fixed2int_var_pixround(xmin);
  83.     y = fixed2int_var_pixround(ymin);
  84.     return
  85.     gx_fill_rectangle_device_rop(x, y,
  86.                      fixed2int_var_pixround(xmax) - x,
  87.                      fixed2int_var_pixround(ymax) - y,
  88.                      pdevc, pfs->dev, pis->log_op);
  89. }
  90.  
  91. /* ================ Specific shadings ================ */
  92.  
  93. /* ---------------- Function-based shading ---------------- */
  94.  
  95. #define Fb_max_depth 32        /* 16 bits each in X and Y */
  96. typedef struct Fb_frame_s {    /* recursion frame */
  97.     gs_rect region;
  98.     gs_client_color cc[4];    /* colors at 4 corners */
  99. } Fb_frame_t;
  100.  
  101. typedef struct Fb_fill_state_s {
  102.     shading_fill_state_common;
  103.     const gs_shading_Fb_t *psh;
  104.     gs_matrix_fixed ptm;    /* parameter space -> device space */
  105.     bool orthogonal;        /* true iff ptm is xxyy or xyyx */
  106.     int depth;            /* 1 <= depth < Fb_max_depth */
  107.     Fb_frame_t frames[Fb_max_depth];
  108. } Fb_fill_state_t;
  109. /****** NEED GC DESCRIPTOR ******/
  110.  
  111. private int
  112. Fb_fill_region(Fb_fill_state_t * pfs)
  113. {
  114.     const gs_shading_Fb_t * const psh = pfs->psh;
  115.     gs_imager_state *pis = pfs->pis;
  116.     Fb_frame_t *fp = &pfs->frames[pfs->depth - 1];
  117.  
  118.     for (;;) {
  119.     const double
  120.         x0 = fp->region.p.x, y0 = fp->region.p.y,
  121.         x1 = fp->region.q.x, y1 = fp->region.q.y;
  122.  
  123.     if (!shade_colors4_converge(fp->cc,
  124.                     (const shading_fill_state_t *)pfs) &&
  125.         fp < &pfs->frames[countof(pfs->frames) - 1]
  126.         ) {
  127.         /*
  128.          * The colors don't converge.  Does the region color more than
  129.          * a single pixel?
  130.          */
  131.         gs_rect region;
  132.  
  133.         gs_bbox_transform(&fp->region, (const gs_matrix *)&pfs->ptm,
  134.                   ®ion);
  135.         if (region.q.x - region.p.x > 1 || region.q.y - region.p.y > 1)
  136.         goto recur;
  137.         {
  138.         /*
  139.          * More precisely, does the bounding box of the region,
  140.          * taking fill adjustment into account, span more than 1
  141.          * pixel center in either X or Y?
  142.          */
  143.         fixed ax = pis->fill_adjust.x;
  144.         int nx =
  145.             fixed2int_pixround(float2fixed(region.q.x) + ax) -
  146.             fixed2int_pixround(float2fixed(region.p.x) - ax);
  147.         fixed ay = pis->fill_adjust.y;
  148.         int ny =
  149.             fixed2int_pixround(float2fixed(region.q.y) + ay) -
  150.             fixed2int_pixround(float2fixed(region.p.y) - ay);
  151.  
  152.         if ((nx > 1 && ny != 0) || (ny > 1 && nx != 0))
  153.             goto recur;
  154.         }
  155.         /* We could do the 1-pixel case a lot faster! */
  156.     }
  157.     /* Fill the region with the color. */
  158.     {
  159.         gx_device_color dev_color;
  160.         const gs_color_space *pcs = psh->params.ColorSpace;
  161.         gs_client_color cc;
  162.         gs_fixed_point pts[4];
  163.         int code;
  164.  
  165.         if_debug0('|', "[|]... filling region\n");
  166.         cc = fp->cc[0];
  167.         (*pcs->type->restrict_color)(&cc, pcs);
  168.         (*pcs->type->remap_color)(&cc, pcs, &dev_color, pis,
  169.                       pfs->dev, gs_color_select_texture);
  170.         gs_point_transform2fixed(&pfs->ptm, x0, y0, &pts[0]);
  171.         gs_point_transform2fixed(&pfs->ptm, x1, y1, &pts[2]);
  172.         if (pfs->orthogonal) {
  173.         code =
  174.             shade_fill_device_rectangle((const shading_fill_state_t *)pfs,
  175.                         &pts[0], &pts[2], &dev_color);
  176.         } else {
  177.         gx_path *ppath = gx_path_alloc(pis->memory, "Fb_fill");
  178.  
  179.         gs_point_transform2fixed(&pfs->ptm, x1, y0, &pts[1]);
  180.         gs_point_transform2fixed(&pfs->ptm, x0, y1, &pts[3]);
  181.         gx_path_add_point(ppath, pts[0].x, pts[0].y);
  182.         gx_path_add_lines(ppath, pts + 1, 3);
  183.         code = shade_fill_path((const shading_fill_state_t *)pfs,
  184.                        ppath, &dev_color);
  185.         gx_path_free(ppath, "Fb_fill");
  186.         }
  187.         if (code < 0 || fp == &pfs->frames[0])
  188.         return code;
  189.         --fp;
  190.         continue;
  191.     }
  192.  
  193.     /*
  194.      * No luck.  Subdivide the region and recur.
  195.      *
  196.      * We should subdivide on the axis that has the largest color
  197.      * discrepancy, but for now we subdivide on the axis with the
  198.      * largest coordinate difference.
  199.      */
  200.     recur:
  201.     {
  202.         gs_function_t *pfn = psh->params.Function;
  203.         float v[2];
  204.         int code;
  205.  
  206.         if (fabs(y1 - y0) > fabs(x1 - x0)) {
  207.         /* Subdivide in Y. */
  208.         double ym = (y0 + y1) * 0.5;
  209.  
  210.         if_debug1('|', "[|]dividing at y=%g\n", ym);
  211.         v[1] = ym;
  212.         v[0] = x0;
  213.         code = gs_function_evaluate(pfn, v, fp[1].cc[2].paint.values);
  214.         if (code < 0)
  215.             return code;
  216.         v[0] = x1;
  217.         code = gs_function_evaluate(pfn, v, fp[1].cc[3].paint.values);
  218.         fp[1].region.q.x = x1;
  219.         fp[1].region.q.y = fp->region.p.y = ym;
  220.         fp[1].cc[0].paint = fp->cc[0].paint;
  221.         fp[1].cc[1].paint = fp->cc[1].paint;
  222.         fp->cc[0].paint = fp[1].cc[2].paint;
  223.         fp->cc[1].paint = fp[1].cc[3].paint;
  224.         } else {
  225.         /* Subdivide in X. */
  226.         double xm = (x0 + x1) * 0.5;
  227.  
  228.         if_debug1('|', "[|]dividing at x=%g\n", xm);
  229.         v[0] = xm;
  230.         v[1] = y0;
  231.         code = gs_function_evaluate(pfn, v, fp[1].cc[1].paint.values);
  232.         if (code < 0)
  233.             return code;
  234.         v[1] = y1;
  235.         code = gs_function_evaluate(pfn, v, fp[1].cc[3].paint.values);
  236.         fp[1].region.q.x = fp->region.p.x = xm;
  237.         fp[1].region.q.y = y1;
  238.         fp[1].cc[0].paint = fp->cc[0].paint;
  239.         fp[1].cc[2].paint = fp->cc[2].paint;
  240.         fp->cc[0].paint = fp[1].cc[1].paint;
  241.         fp->cc[2].paint = fp[1].cc[3].paint;
  242.         }
  243.         if (code < 0)
  244.         return code;
  245.         fp[1].region.p.x = x0, fp[1].region.p.y = y0;
  246.         ++fp;
  247.     }
  248.     }
  249. }
  250.  
  251. int
  252. gs_shading_Fb_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect,
  253.                  gx_device * dev, gs_imager_state * pis)
  254. {
  255.     const gs_shading_Fb_t * const psh = (const gs_shading_Fb_t *)psh0;
  256.     gs_matrix save_ctm;
  257.     int xi, yi;
  258.     float x[2], y[2];
  259.     Fb_fill_state_t state;
  260.  
  261.     shade_init_fill_state((shading_fill_state_t *) & state, psh0, dev, pis);
  262.     state.psh = psh;
  263.     /****** HACK FOR FIXED-POINT MATRIX MULTIPLY ******/
  264.     gs_currentmatrix((gs_state *) pis, &save_ctm);
  265.     gs_concat((gs_state *) pis, &psh->params.Matrix);
  266.     state.ptm = pis->ctm;
  267.     gs_setmatrix((gs_state *) pis, &save_ctm);
  268.     state.orthogonal = is_xxyy(&state.ptm) || is_xyyx(&state.ptm);
  269.     /* Compute the parameter X and Y ranges. */
  270.     {
  271.     gs_rect pbox;
  272.  
  273.     gs_bbox_transform_inverse(rect, &psh->params.Matrix, &pbox);
  274.     x[0] = max(pbox.p.x, psh->params.Domain[0]);
  275.     x[1] = min(pbox.q.x, psh->params.Domain[1]);
  276.     y[0] = max(pbox.p.y, psh->params.Domain[2]);
  277.     y[1] = min(pbox.q.y, psh->params.Domain[3]);
  278.     }
  279.     for (xi = 0; xi < 2; ++xi)
  280.     for (yi = 0; yi < 2; ++yi) {
  281.         float v[2];
  282.  
  283.         v[0] = x[xi], v[1] = y[yi];
  284.         gs_function_evaluate(psh->params.Function, v,
  285.                  state.frames[0].cc[yi * 2 + xi].paint.values);
  286.     }
  287.     state.frames[0].region.p.x = x[0];
  288.     state.frames[0].region.p.y = y[0];
  289.     state.frames[0].region.q.x = x[1];
  290.     state.frames[0].region.q.y = y[1];
  291.     state.depth = 1;
  292.     return Fb_fill_region(&state);
  293. }
  294.  
  295. /* ---------------- Axial shading ---------------- */
  296.  
  297. /*
  298.  * Note that the max recursion depth and the frame structure are shared
  299.  * with radial shading.
  300.  */
  301. #define AR_max_depth 16
  302. typedef struct AR_frame_s {    /* recursion frame */
  303.     double t0, t1;
  304.     gs_client_color cc[2];    /* color at t0, t1 */
  305. } AR_frame_t;
  306.  
  307. #define A_max_depth AR_max_depth
  308. typedef AR_frame_t A_frame_t;
  309.  
  310. typedef struct A_fill_state_s {
  311.     shading_fill_state_common;
  312.     const gs_shading_A_t *psh;
  313.     bool orthogonal;        /* true iff ctm is xxyy or xyyx */
  314.     gs_rect rect;        /* bounding rectangle in user space */
  315.     gs_point delta;
  316.     double length, dd;
  317.     int depth;
  318.     A_frame_t frames[A_max_depth];
  319. } A_fill_state_t;
  320. /****** NEED GC DESCRIPTOR ******/
  321.  
  322. /* Note t0 and t1 vary over [0..1], not the Domain. */
  323.  
  324. private int
  325. A_fill_stripe(const A_fill_state_t * pfs, gs_client_color *pcc,
  326.           floatp t0, floatp t1)
  327. {
  328.     const gs_shading_A_t * const psh = pfs->psh;
  329.     gx_device_color dev_color;
  330.     const gs_color_space *pcs = psh->params.ColorSpace;
  331.     gs_imager_state *pis = pfs->pis;
  332.     double
  333.     x0 = psh->params.Coords[0] + pfs->delta.x * t0,
  334.     y0 = psh->params.Coords[1] + pfs->delta.y * t0;
  335.     double
  336.     x1 = psh->params.Coords[0] + pfs->delta.x * t1,
  337.     y1 = psh->params.Coords[1] + pfs->delta.y * t1;
  338.     gs_fixed_point pts[4];
  339.     int code;
  340.  
  341.     (*pcs->type->restrict_color)(pcc, pcs);
  342.     (*pcs->type->remap_color)(pcc, pcs, &dev_color, pis,
  343.                   pfs->dev, gs_color_select_texture);
  344.     if (x0 == x1 && pfs->orthogonal) {
  345.     /*
  346.      * Stripe is horizontal in user space and horizontal or vertical
  347.      * in device space.
  348.      */
  349.     x0 = pfs->rect.p.x;
  350.     x1 = pfs->rect.q.x;
  351.     } else if (y0 == y1 && pfs->orthogonal) {
  352.     /*
  353.      * Stripe is vertical in user space and horizontal or vertical
  354.      * in device space.
  355.      */
  356.     y0 = pfs->rect.p.y;
  357.     y1 = pfs->rect.q.y;
  358.     } else {
  359.     /*
  360.      * Stripe is neither horizontal nor vertical in user space.
  361.      * Extend it to the edges of the (user-space) rectangle.
  362.      */
  363.     gx_path *ppath = gx_path_alloc(pis->memory, "A_fill");
  364.     if (fabs(pfs->delta.x) < fabs(pfs->delta.y)) {
  365.         /*
  366.          * Calculate intersections with vertical sides of rect.
  367.          */
  368.         double slope = pfs->delta.x / pfs->delta.y;
  369.         double yi = y0 - slope * (pfs->rect.p.x - x0);
  370.  
  371.         gs_point_transform2fixed(&pis->ctm, pfs->rect.p.x, yi, &pts[0]);
  372.         yi = y1 - slope * (pfs->rect.p.x - x1);
  373.         gs_point_transform2fixed(&pis->ctm, pfs->rect.p.x, yi, &pts[1]);
  374.         yi = y1 - slope * (pfs->rect.q.x - x1);
  375.         gs_point_transform2fixed(&pis->ctm, pfs->rect.q.x, yi, &pts[2]);
  376.         yi = y0 - slope * (pfs->rect.q.x - x0);
  377.         gs_point_transform2fixed(&pis->ctm, pfs->rect.q.x, yi, &pts[3]);
  378.     }
  379.     else {
  380.         /*
  381.          * Calculate intersections with horizontal sides of rect.
  382.          */
  383.         double slope = pfs->delta.y / pfs->delta.x;
  384.         double xi = x0 - slope * (pfs->rect.p.y - y0);
  385.  
  386.         gs_point_transform2fixed(&pis->ctm, xi, pfs->rect.p.y, &pts[0]);
  387.         xi = x1 - slope * (pfs->rect.p.y - y1);
  388.         gs_point_transform2fixed(&pis->ctm, xi, pfs->rect.p.y, &pts[1]);
  389.         xi = x1 - slope * (pfs->rect.q.y - y1);
  390.         gs_point_transform2fixed(&pis->ctm, xi, pfs->rect.q.y, &pts[2]);
  391.         xi = x0 - slope * (pfs->rect.q.y - y0);
  392.         gs_point_transform2fixed(&pis->ctm, xi, pfs->rect.q.y, &pts[3]);
  393.     }
  394.     gx_path_add_point(ppath, pts[0].x, pts[0].y);
  395.     gx_path_add_lines(ppath, pts + 1, 3);
  396.     code = shade_fill_path((const shading_fill_state_t *)pfs,
  397.                    ppath, &dev_color);
  398.     gx_path_free(ppath, "A_fill");
  399.     return code;
  400.     }
  401.     /* Stripe is horizontal or vertical in both user and device space. */
  402.     gs_point_transform2fixed(&pis->ctm, x0, y0, &pts[0]);
  403.     gs_point_transform2fixed(&pis->ctm, x1, y1, &pts[1]);
  404.     return
  405.     shade_fill_device_rectangle((const shading_fill_state_t *)pfs,
  406.                     &pts[0], &pts[1], &dev_color);
  407. }
  408.  
  409. private int
  410. A_fill_region(A_fill_state_t * pfs)
  411. {
  412.     const gs_shading_A_t * const psh = pfs->psh;
  413.     gs_function_t * const pfn = psh->params.Function;
  414.     A_frame_t *fp = &pfs->frames[pfs->depth - 1];
  415.  
  416.     for (;;) {
  417.     double t0 = fp->t0, t1 = fp->t1;
  418.     float ft0, ft1;
  419.  
  420.     if ((!(pfn->head.is_monotonic > 0 ||
  421.            (ft0 = (float)t0, ft1 = (float)t1,
  422.         gs_function_is_monotonic(pfn, &ft0, &ft1, EFFORT_MODERATE) > 0)) ||
  423.          !shade_colors2_converge(fp->cc,
  424.                      (const shading_fill_state_t *)pfs)) &&
  425.          /*
  426.           * The function isn't monotonic, or the colors don't converge.
  427.           * Is the stripe less than 1 pixel wide?
  428.           */
  429.         pfs->length * (t1 - t0) > 1 &&
  430.         fp < &pfs->frames[countof(pfs->frames) - 1]
  431.         ) {
  432.         /* Subdivide the interval and recur.  */
  433.         double tm = (t0 + t1) * 0.5;
  434.         float dm = tm * pfs->dd + psh->params.Domain[0];
  435.  
  436.         gs_function_evaluate(pfn, &dm, fp[1].cc[1].paint.values);
  437.         fp[1].cc[0].paint = fp->cc[0].paint;
  438.         fp[1].t0 = t0;
  439.         fp[1].t1 = fp->t0 = tm;
  440.         fp->cc[0].paint = fp[1].cc[1].paint;
  441.         ++fp;
  442.     } else {
  443.         /* Fill the region with the color. */
  444.         int code = A_fill_stripe(pfs, &fp->cc[0], t0, t1);
  445.  
  446.         if (code < 0 || fp == &pfs->frames[0])
  447.         return code;
  448.         --fp;
  449.     }
  450.     }
  451. }
  452.  
  453. int
  454. gs_shading_A_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect,
  455.                 gx_device * dev, gs_imager_state * pis)
  456. {
  457.     const gs_shading_A_t *const psh = (const gs_shading_A_t *)psh0;
  458.     gs_matrix cmat;
  459.     gs_rect t_rect;
  460.     A_fill_state_t state;
  461.     gs_client_color rcc[2];
  462.     float d0 = psh->params.Domain[0], d1 = psh->params.Domain[1];
  463.     float dd = d1 - d0;
  464.     float t0, t1;
  465.     float t[2];
  466.     gs_point dist;
  467.     int i;
  468.     int code;
  469.  
  470.     shade_init_fill_state((shading_fill_state_t *)&state, psh0, dev, pis);
  471.     state.psh = psh;
  472.     state.orthogonal = is_xxyy(&pis->ctm) || is_xyyx(&pis->ctm);
  473.     state.rect = *rect;
  474.     /*
  475.      * Compute the parameter range.  We construct a matrix in which
  476.      * (0,0) corresponds to t = 0 and (0,1) corresponds to t = 1,
  477.      * and use it to inverse-map the rectangle to be filled.
  478.      */
  479.     cmat.tx = psh->params.Coords[0];
  480.     cmat.ty = psh->params.Coords[1];
  481.     state.delta.x = psh->params.Coords[2] - psh->params.Coords[0];
  482.     state.delta.y = psh->params.Coords[3] - psh->params.Coords[1];
  483.     cmat.yx = state.delta.x;
  484.     cmat.yy = state.delta.y;
  485.     cmat.xx = cmat.yy;
  486.     cmat.xy = -cmat.yx;
  487.     gs_bbox_transform_inverse(rect, &cmat, &t_rect);
  488.     state.frames[0].t0 = t0 = max(t_rect.p.y, 0);
  489.     t[0] = t0 * dd + d0;
  490.     state.frames[0].t1 = t1 = min(t_rect.q.y, 1);
  491.     t[1] = t1 * dd + d0;
  492.     for (i = 0; i < 2; ++i) {
  493.     gs_function_evaluate(psh->params.Function, &t[i],
  494.                  rcc[i].paint.values);
  495.     }
  496.     memcpy(state.frames[0].cc, rcc, sizeof(rcc[0]) * 2);
  497.     gs_distance_transform(state.delta.x, state.delta.y, &ctm_only(pis),
  498.               &dist);
  499.     state.length = hypot(dist.x, dist.y);    /* device space line length */
  500.     state.dd = dd;
  501.     state.depth = 1;
  502.     code = A_fill_region(&state);
  503.     if (psh->params.Extend[0] && t0 > t_rect.p.y) {
  504.     if (code < 0)
  505.         return code;
  506.     code = A_fill_stripe(&state, &rcc[0], t_rect.p.y, t0);
  507.     }
  508.     if (psh->params.Extend[1] && t1 < t_rect.q.y) {
  509.     if (code < 0)
  510.         return code;
  511.     code = A_fill_stripe(&state, &rcc[1], t1, t_rect.q.y);
  512.     }
  513.     return code;
  514. }
  515.  
  516. /* ---------------- Radial shading ---------------- */
  517.  
  518. #define R_max_depth AR_max_depth
  519. typedef AR_frame_t R_frame_t;
  520.  
  521. typedef struct R_fill_state_s {
  522.     shading_fill_state_common;
  523.     const gs_shading_R_t *psh;
  524.     gs_rect rect;
  525.     gs_point delta;
  526.     double dr, width, dd;
  527.     int depth;
  528.     R_frame_t frames[R_max_depth];
  529. } R_fill_state_t;
  530. /****** NEED GC DESCRIPTOR ******/
  531.  
  532. /* Note t0 and t1 vary over [0..1], not the Domain. */
  533.  
  534. private int
  535. R_fill_annulus(const R_fill_state_t * pfs, gs_client_color *pcc,
  536.            floatp t0, floatp t1, floatp r0, floatp r1)
  537. {
  538.     const gs_shading_R_t * const psh = pfs->psh;
  539.     gx_device_color dev_color;
  540.     const gs_color_space *pcs = psh->params.ColorSpace;
  541.     gs_imager_state *pis = pfs->pis;
  542.     double
  543.     x0 = psh->params.Coords[0] + pfs->delta.x * t0,
  544.     y0 = psh->params.Coords[1] + pfs->delta.y * t0;
  545.     double
  546.     x1 = psh->params.Coords[0] + pfs->delta.x * t1,
  547.     y1 = psh->params.Coords[1] + pfs->delta.y * t1;
  548.     gx_path *ppath = gx_path_alloc(pis->memory, "R_fill");
  549.     int code;
  550.  
  551.     (*pcs->type->restrict_color)(pcc, pcs);
  552.     (*pcs->type->remap_color)(pcc, pcs, &dev_color, pis,
  553.                   pfs->dev, gs_color_select_texture);
  554.     if ((code = gs_imager_arc_add(ppath, pis, false, x0, y0, r0,
  555.                   0.0, 360.0, false)) >= 0 &&
  556.     (code = gs_imager_arc_add(ppath, pis, true, x1, y1, r1,
  557.                   360.0, 0.0, false)) >= 0
  558.     ) {
  559.     code = shade_fill_path((const shading_fill_state_t *)pfs,
  560.                    ppath, &dev_color);
  561.     }
  562.     gx_path_free(ppath, "R_fill");
  563.     return code;
  564. }
  565.  
  566. private int
  567. R_fill_region(R_fill_state_t * pfs)
  568. {
  569.     const gs_shading_R_t * const psh = pfs->psh;
  570.     gs_function_t *pfn = psh->params.Function;
  571.     R_frame_t *fp = &pfs->frames[pfs->depth - 1];
  572.  
  573.     for (;;) {
  574.     double t0 = fp->t0, t1 = fp->t1;
  575.     float ft0, ft1;
  576.  
  577.     if ((!(pfn->head.is_monotonic > 0 ||
  578.            (ft0 = (float)t0, ft1 = (float)t1,
  579.         gs_function_is_monotonic(pfn, &ft0, &ft1, EFFORT_MODERATE) > 0)) ||
  580.          !shade_colors2_converge(fp->cc,
  581.                      (const shading_fill_state_t *)pfs)) &&
  582.         /*
  583.          * The function isn't monotonic, or the colors don't converge.
  584.          * Is the annulus less than 1 pixel wide?
  585.          */
  586.         pfs->width * (t1 - t0) > 1 &&
  587.         fp < &pfs->frames[countof(pfs->frames) - 1]
  588.        ) {
  589.         /* Subdivide the interval and recur.  */
  590.         float tm = (t0 + t1) * 0.5;
  591.         float dm = tm * pfs->dd + psh->params.Domain[0];
  592.  
  593.         gs_function_evaluate(pfn, &dm, fp[1].cc[1].paint.values);
  594.         fp[1].cc[0].paint = fp->cc[0].paint;
  595.         fp[1].t0 = t0;
  596.         fp[1].t1 = fp->t0 = tm;
  597.         fp->cc[0].paint = fp[1].cc[1].paint;
  598.         ++fp;
  599.     } else {
  600.         /* Fill the region with the color. */
  601.         int code = R_fill_annulus(pfs, &fp->cc[0], t0, t1,
  602.                       psh->params.Coords[2] + pfs->dr * t0,
  603.                       psh->params.Coords[2] + pfs->dr * t1);
  604.  
  605.         if (code < 0 || fp == &pfs->frames[0])
  606.         return code;
  607.         --fp;
  608.     }
  609.     }
  610. }
  611.  
  612. private double
  613. R_compute_radius(floatp x, floatp y, const gs_rect *rect)
  614. {
  615.     double x0 = rect->p.x - x, y0 = rect->p.y - y,
  616.     x1 = rect->q.x - x, y1 = rect->q.y - y;
  617.     double r00 = hypot(x0, y0), r01 = hypot(x0, y1),
  618.     r10 = hypot(x1, y0), r11 = hypot(x1, y1);
  619.     double rm0 = max(r00, r01), rm1 = max(r10, r11);
  620.  
  621.     return max(rm0, rm1);
  622. }
  623.  
  624. int
  625. gs_shading_R_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect,
  626.                 gx_device * dev, gs_imager_state * pis)
  627. {
  628.     const gs_shading_R_t *const psh = (const gs_shading_R_t *)psh0;
  629.     R_fill_state_t state;
  630.     gs_client_color rcc[2];
  631.     float d0 = psh->params.Domain[0], d1 = psh->params.Domain[1];
  632.     float dd = d1 - d0;
  633.     float x0 = psh->params.Coords[0], y0 = psh->params.Coords[1];
  634.     floatp r0 = psh->params.Coords[2];
  635.     float x1 = psh->params.Coords[3], y1 = psh->params.Coords[4];
  636.     floatp r1 = psh->params.Coords[5];
  637.     float t[2];
  638.     int i;
  639.     int code;
  640.  
  641.     shade_init_fill_state((shading_fill_state_t *)&state, psh0, dev, pis);
  642.     state.psh = psh;
  643.     state.rect = *rect;
  644.     /* Compute the parameter range. */
  645.     t[0] = d0;
  646.     t[1] = d1;
  647.     for (i = 0; i < 2; ++i)
  648.     gs_function_evaluate(psh->params.Function, &t[i],
  649.                  rcc[i].paint.values);
  650.     memcpy(state.frames[0].cc, rcc, sizeof(rcc[0]) * 2);
  651.     state.delta.x = x1 - x0;
  652.     state.delta.y = y1 - y0;
  653.     state.dr = r1 - r0;
  654.     /*
  655.      * Compute the annulus width in its thickest direction.  This is
  656.      * only used for a conservative check, so it can be pretty crude
  657.      * (and it is!).
  658.      */
  659.     state.width =
  660.     (fabs(pis->ctm.xx) + fabs(pis->ctm.xy) + fabs(pis->ctm.yx) +
  661.      fabs(pis->ctm.yy)) * fabs(state.dr);
  662.     state.dd = dd;
  663.     if (psh->params.Extend[0]) {
  664.     if (r0 < r1)
  665.         code = R_fill_annulus(&state, &rcc[0], 0.0, 0.0, 0.0, r0);
  666.     else
  667.         code = R_fill_annulus(&state, &rcc[0], 0.0, 0.0, r0,
  668.                   R_compute_radius(x0, y0, rect));
  669.     if (code < 0)
  670.         return code;
  671.     }
  672.     state.depth = 1;
  673.     state.frames[0].t0 = (t[0] - d0) / dd;
  674.     state.frames[0].t1 = (t[1] - d0) / dd;
  675.     code = R_fill_region(&state);
  676.     if (psh->params.Extend[1]) {
  677.     if (code < 0)
  678.         return code;
  679.     if (r0 < r1)
  680.         code = R_fill_annulus(&state, &rcc[1], 1.0, 1.0, r1,
  681.                   R_compute_radius(x1, y1, rect));
  682.     else
  683.         code = R_fill_annulus(&state, &rcc[1], 1.0, 1.0, 0.0, r1);
  684.     }
  685.     return code;
  686. }
  687.